﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Collections;

namespace Infinity.ExpressionParser.Comparer
{
	public class ObjectEqualityComparer : IEqualityComparer<object>
	{
		protected static List<IEnumerable> setList = new List<IEnumerable>();

		protected static ObjectEqualityComparer instance = new ObjectEqualityComparer();

		protected ObjectEqualityComparer() { }

		protected bool ArrayEquals(IEnumerable<object> a, IEnumerable<object> b)
		{
			//if (a != null && b != null)
			//{
				var arrayOne = a.OrderBy(obj => obj.GetHashCode());
				var arrayTwo = b.OrderBy(obj => obj.GetHashCode());
				bool result = true;

				foreach (var x in arrayOne)
				{
					foreach (var y in arrayTwo)
					{
						if (x is IEnumerable<object> && y is IEnumerable<object>)
						{
							result = result && ArrayEquals(x as IEnumerable<object>, y as IEnumerable<object>);
						}
						else if (!x.Equals(y))
						{
							return false;
						}
					}
				}

				return result;
			//}
			//else
			//{
			//    return false;
			//}
		}

		public static ObjectEqualityComparer Instance
		{
			get
			{
				return instance;
			}
		}

		public new bool Equals(object x, object y)
		{
			if (x is IEnumerable<object> && y is IEnumerable<object>)
			{
				return ArrayEquals(x as IEnumerable<object>, y as IEnumerable<object>);
			}
			return x.Equals(y);
		}

		public int GetHashCode(object obj)
		{
			if (obj is IEnumerable && !(obj is string))
			{
				var array = obj as IEnumerable<object>;
				var match = setList.Where(s => this.ArrayEquals(s.Cast<object>(), array));
				if (match.Count() > 0)
				{
					return match.First().GetHashCode();
				}
				else
				{
					setList.Add(array);
					return array.GetHashCode();
				}
			}
			return obj.GetHashCode();
		}
	}
}
